using Furion;
using Furion.Reflection;

using Microsoft.AspNetCore.Http;

using System;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;

using Tool;

namespace Abc.Application
{
    /// <summary>
    /// AOP 拦截
    /// 全局：IGlobalDispatchProxy
    /// 自定义：IDispatchProxy   使用：[Injection(Proxy = typeof(LogDispatchProxy))]
    /// </summary>
    public class LogDispatchProxy : AspectDispatchProxy, IDispatchProxy
    {
        /// <summary>
        /// 当前服务实例
        /// </summary>
        public object Target { get; set; }

        /// <summary>
        /// 服务提供器，可以用来解析服务，如：Services.GetService()
        /// </summary>
        public IServiceProvider Services { get; set; }

        /// <summary>
        /// 日志文件目录
        /// </summary>
        public string LogFloderName { get; set; }

        /// <summary>
        /// 日志内容
        /// </summary>
        public string LogContent { get; set; }

        /// <summary>
        /// 拦截方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public override object Invoke(MethodInfo method, object[] args)
        {
            try
            {
                //var a = JSON.Serialize("123465");
                StartMethod(method, args);
                var result = method.Invoke(Target, args);
                LogContent = LogContent.AppendLine($"返回：{JsonSerializer.Serialize(result, AppEx.GetDefaultJsonSerializerOptions)}");
                return result;
            }
            catch (Exception ex)
            {
                LogContent = LogContent.AppendLine($"异常：{ex.ToStringEx()}");
                throw;
            }
            finally
            {
                AppEx.GetLogger(logFloderName: LogFloderName, retainedFileCountLimit: 30).Debug(LogContent);
            }
        }

        /// <summary>
        /// 异步无返回值
        /// </summary>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public override async Task InvokeAsync(MethodInfo method, object[] args)
        {
            try
            {
                StartMethod(method, args);

                var task = method.Invoke(Target, args) as Task;
                await task;
            }
            catch (Exception ex)
            {
                LogContent = LogContent.AppendLine($"异常：{ex.ToStringEx()}");
                throw;
            }
            finally
            {
                AppEx.GetLogger(logFloderName: LogFloderName, retainedFileCountLimit: 30).Debug(LogContent);
            }
        }

        /// <summary>
        /// 异步带返回值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public override async Task<T> InvokeAsyncT<T>(MethodInfo method, object[] args)
        {
            try
            {
                StartMethod(method, args);

                var taskT = method.Invoke(Target, args) as Task<T>;
                var result = await taskT;
                LogContent = LogContent.AppendLine($"返回：{JsonSerializer.Serialize(result, AppEx.GetDefaultJsonSerializerOptions)}");
                return result;
            }
            catch (Exception ex)
            {
                LogContent = LogContent.AppendLine($"异常：{ex.ToStringEx()}");
                throw;
            }
            finally
            {
                AppEx.GetLogger(logFloderName: LogFloderName, retainedFileCountLimit: 30).Debug(LogContent);
            }
        }

        /// <summary>
        /// 调用方法前
        /// </summary>
        /// <param name="method"></param>
        /// <param name="args"></param>
        private void StartMethod(MethodInfo method, object[] args)
        {
            var httpcontext = App.GetService<IHttpContextAccessor>();
            LogContent = LogContent.AppendLine(httpcontext?.HttpContext?.GetVisitInfo() ?? "");
            var servicename = method.ReflectedType.Name;
            LogFloderName = $"AOP\\{servicename}";
            LogContent = LogContent.AppendLine($"调用命名空间 {method?.DeclaringType?.FullName} --> {method?.Name}  \r\n参数：{JsonSerializer.Serialize(args, AppEx.GetDefaultJsonSerializerOptions)}");
        }
    }
}